using System;
using System.Collections.Generic;
using System.Threading;

using Sce.Pss.HighLevel.GameEngine2D;
using Sce.Pss.HighLevel.GameEngine2D.Base;
using Sce.Pss.HighLevel.Physics2D;
using Sce.Pss.Core.Audio;

using Sce.Pss.Core;
using Sce.Pss.Core.Environment;
using Sce.Pss.Core.Graphics;
using Sce.Pss.Core.Imaging;
using Sce.Pss.Core.Input;

using System.IO;
using System.Net;
using System.Xml;
using System.Runtime;
using System.ComponentModel;
using System.Xml.Serialization;

namespace RedSkies
{
	public class RedSkiesGame
	{
		private Scene _Scene;
		private SpriteList _SpriteList;
		private SpriteList _SpriteListEnemies;
		private SpriteList _SpriteListFlyEnemies;
		private SpriteList _SpriteListFire;
		
		private WorldMatrix MyMatrix;
		private WorldView worldView;
	
		//private static List<SpriteUV> _Sprites=new List<SpriteUV>();
		protected PlayerSprite Player;
		protected List<StupidEnemySprite> Enemies= new List<StupidEnemySprite>();
		protected List<StupidEnemySprite> FlyingEnemies= new List<StupidEnemySprite>();
		
		private List<FireSprite> _Fire=new List<FireSprite>();
		private List<FireSprite> _AktuellesFire=new List<FireSprite>();
		
		private int aktuellesFeuer=0;
		
		private GameState _GameState;
				
		private SpriteUV SpriteBack;
						
		private FpsWaiter fpsWaiter;
		private Bgm musikStueck;
		private BgmPlayer musikPlayer;
		
		public RedSkiesGame ()
		{	
		}
		
		void AddPlayer ()
		{
			TextureInfo textureInfo = LoadTexture(@"/Application/graphix/helverian.png");
			_SpriteList = new SpriteList(textureInfo);
		//_SpriteList.BlendMode = new BlendMode(true, new BlendFunc(BlendFuncMode.Add,BlendFuncFactor.One,BlendFuncFactor.DstAlpha));
									
			Player = new PlayerSprite(textureInfo, _Scene.Camera.CalcBounds().Center, MyMatrix, 5, _SpriteList);
			
			//Player.BlendMode = new BlendMode(true, new BlendFunc(BlendFuncMode.Subtract,BlendFuncFactor.SrcAlpha,BlendFuncFactor.DstAlpha));
			
			_SpriteList.AddChild(Player);		
		}

		void AddEnemies ()
		{
			TextureInfo textureInfo = LoadTexture(@"/Application/graphix/grey.png");
			_SpriteListEnemies = new SpriteList(textureInfo);
			
			Random r = new Random();
			
			for (int i=0;i<4;i++)
			{
				Vector2 v = _Scene.Camera.CalcBounds().Center;
				v.X = (float)v.X + (float)(r.NextDouble() * 900) -450;
				
				StupidEnemySprite e = new StupidEnemySprite(textureInfo, v, MyMatrix, 5, _SpriteListEnemies);
				
				Enemies.Add(e);
				_SpriteListEnemies.AddChild(e);		
			}
		}

		void AddFlyingEnemies ()
		{
			TextureInfo textureInfo = LoadTexture(@"/Application/graphix/hack.png");
			_SpriteListFlyEnemies = new SpriteList(textureInfo);
			
			Random r = new Random();
			
			for (int i=0;i<10;i++)
			{
				Vector2 v = _Scene.Camera.CalcBounds().Center;
				v.X = (float)v.X + (float)(r.NextDouble() * 900) -450;
				v.Y = (float)v.Y + (float)(r.NextDouble() * 100) -110;
				
				StupidEnemySprite e = new StupidEnemySprite(textureInfo, v, MyMatrix, 5, _SpriteListFlyEnemies);
				e.Flying=true;
				e.Quad.S = textureInfo.TextureSizef;
				
				Enemies.Add(e);
				_SpriteListFlyEnemies.AddChild(e);		
			}
		}
		
		void AddFire ()
		{
			TextureInfo f2dInfo = LoadTexture(@"/Application/graphix/fire.png");
						
			_SpriteListFire = new SpriteList(f2dInfo);
			
			for (int i=0;i<5;i++)
			{
				FireSprite fire = new FireSprite();
				fire.Quad.S = new Vector2(10,10);
				
				fire.Position = new Vector2(-100,-100);
				_Fire.Add(fire);
				_SpriteListFire.AddChild(fire);
			}
		}

		void AddBackground ()
		{
			//			Player = new PlayerSprite(textureInfo, _Scene.Camera.CalcBounds().Center, MyMatrix, 5);
//			Player.BlendMode = new BlendMode(true, new BlendFunc(BlendFuncMode.Subtract,BlendFuncFactor.SrcAlpha,BlendFuncFactor.DstAlpha));

			TextureInfo tBack = LoadTexture(@"/Application/graphix/dunkelrot.png");
			MyMatrix.ListOfTextures.Add(tBack);
			MyMatrix.SpriteListMap.Add(new SpriteList(tBack));
			SpriteBack = new SpriteUV();
			SpriteBack.Position=new Vector2(0,0);
			SpriteBack.Quad.S = new Vector2(960,560);
			MyMatrix.SpriteListMap[0].AddChild(SpriteBack);
		}
		
		public void Initialize()
		{
			musikStueck = new Bgm(@"/Application/musix/redskies1.mp3");
			musikPlayer = musikStueck.CreatePlayer();
			
			musikPlayer.Play();
			
			musikPlayer.Loop = true;
			
			fpsWaiter = new FpsWaiter(FpsMax.Fps60);
			
			try {
				LevelMapLoader w = new LevelMapLoader();
				MyMatrix = w.CreateInitialLevelMapMatrix();
				
				_GameState = GameState.Initializing;
				GraphixXmlFileMapper gxfm;
				
        		gxfm = new GraphixXmlFileMapper();
				
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/blue.png", 1));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/pink.png", 2));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/grey.png", 3));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/leftabovestone.png", 4));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/abovestone.png", 5));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/rightabovestone.png", 6));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/leftstone.png", 7));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/middlestone.png", 8));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/rightstone.png", 9));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/leftdownstone.png", 10));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/downstone.png", 11));
				gxfm.ListOfElementsForMap.Add(new GraphixElement(@"/Application/graphix/rightdownstone.png", 12));			
				
				
				
				Log.SetToConsole();
												
				Director.Initialize();

				//Director.Instance.GL.Context.SetClearColor(Colors.Grey20);
				
				_Scene = new Scene();
				_Scene.Camera.SetViewFromViewport();

				AddBackground ();
				
				worldView = new WorldView(_Scene.Camera2D, this.SpriteBack, MyMatrix);				
				
				foreach (GraphixElement ge in gxfm.ListOfElementsForMap)
				{
					TextureInfo tI = LoadTexture(ge.FileName);
					MyMatrix.ListOfTextures.Add(tI);
					MyMatrix.SpriteListMap.Add(new SpriteList(tI));
				}				
				
				AddPlayer ();
				
				AddEnemies ();
				
				AddFlyingEnemies();
					
				AddFire ();
				
				MyMatrix.CreateInitialWorld();									
				
				foreach(SpriteList sl in MyMatrix.SpriteListMap)
				{
					_Scene.AddChild(sl);
				}
				
				_Scene.AddChild(_SpriteList);
				_Scene.AddChild(_SpriteListEnemies);
				_Scene.AddChild(_SpriteListFlyEnemies);
				_Scene.AddChild(_SpriteListFire);			
								
				
				Director.Instance.RunWithScene(_Scene, true);
			} catch (Exception e)
			{				
			Console.WriteLine(e.StackTrace);
				throw;
			}
		}
		
		public void Cleanup()
		{
			musikPlayer.Stop();
			musikPlayer.Dispose();
			musikStueck.Dispose();
			Director.Terminate();
		}		

		public void GameLoop()
		{						
			_GameState = GameState.Running;
			
			while (_GameState != GameState.Ending)
			{
				fpsWaiter.WaitForSync();
				
				SystemEvents.CheckEvents();
				Update();
				Render();
			}
		}
		
		void HandleNewFire ()
		{
			FireSprite fire = _Fire[aktuellesFeuer];
			fire.Position = new Vector2(Player.GetRect().X+Player.GetRect().Width + 10, Player.GetRect().Y+Player.GetRect().Height -40);
			fire.ResetFire();
			
			if (!_AktuellesFire.Contains(fire))
			{
				_AktuellesFire.Add(fire);
			}
			
			aktuellesFeuer++;
			if (aktuellesFeuer == 5)
			{
				aktuellesFeuer=0;
			}
		}		

		void HandleActionButtons ()
		{
			GamePadData gamePadData = GamePad.GetData(0);
			
			if(gamePadData.IsCrossPressed())
			{
				HandleNewFire ();
			}			
			
			if (gamePadData.IsL1Pressed())
			{
				_GameState = GameState.Ending;
			}
		}

		bool PlayerDiedBecauseOfFalling (Rectangle rectNew)
		{
			return rectNew.Y<0;
		}
	
		private void Update()
		{
			Rectangle rectOld = Player.GetRect();
									
			Rectangle rectNew =Player.Update();
			
			worldView.UpdateWorld(rectOld, rectNew);			
						
			if (PlayerDiedBecauseOfFalling (rectNew))
			{
				_GameState = GameState.Ending;	
			}
			
			List<StupidEnemySprite> killedEnemies = new List<StupidEnemySprite>();
				
			foreach (StupidEnemySprite s in Enemies)
			{
				s.Update();
				if (s.Position.Y < 0)
				{
					killedEnemies.Add(s);
				}
				foreach(FireSprite fs in _AktuellesFire) 
				{
					Rectangle r= fs.GetRect();
					Rectangle r2 = s.GetRect();
					if (r.X+(r.Width/2) > r2.X &&
					    r.X+(r.Width/2) < r2.X+r2.Width
					    &&
					    r.Y+(r.Height/2) > r2.Y &&
					    r.Y+(r.Height/2) < r2.Y+r2.Height)
					{
						killedEnemies.Add(s);
					}
				}
			}
			foreach (StupidEnemySprite s in FlyingEnemies)
			{
				s.Update();
				if (s.Position.Y < 0)
				{
					killedEnemies.Add(s);
				}
				foreach(FireSprite fs in _AktuellesFire) 
				{
					Rectangle r= fs.GetRect();
					Rectangle r2 = s.GetRect();
					if (r.X+(r.Width/2) > r2.X &&
					    r.X+(r.Width/2) < r2.X+r2.Width
					    &&
					    r.Y+(r.Height/2) > r2.Y &&
					    r.Y+(r.Height/2) < r2.Y+r2.Height)
					{
						killedEnemies.Add(s);
					}
				}
			}
			
			foreach (StupidEnemySprite s in FlyingEnemies)
			{
				s.Update();
			}			

			foreach (StupidEnemySprite s in killedEnemies)
			{
				this.Enemies.Remove(s);
				s.DeleteSprite();
				Enemies.Remove(s);
			}
			
			HandleActionButtons ();
			
			FireUpdate();
			
			Director.Instance.Update();
		}
		
		private void FireUpdate()
		{
			foreach (FireSprite fs in _AktuellesFire)
			{	
				fs.Update(GamePad.GetData(0));
			}
			foreach (FireSprite fs in new List<FireSprite>(_AktuellesFire))
			{
				if (fs.AtEndOfAnimation())
				{
					_AktuellesFire.Remove(fs);
					fs.Position = new Vector2(-100,-100);
				}
			}
		}
		
		private void Render()
		{
			Director.Instance.Render();
			Director.Instance.GL.Context.SwapBuffers();
			Director.Instance.PostSwap();
		}
		
		public static TextureInfo LoadTexture(string filename)
		{
			return new TextureInfo(new Texture2D(filename, false));
		}			
	}
}